package net.zoneland.greenleaf.timer.task;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.zoneland.greenleaf.GLOBAL;
import net.zoneland.greenleaf.common.date.DateOperation;
import net.zoneland.greenleaf.timer.entity.Log_timer_runlog;
import net.zoneland.greenleaf.timer.entity.Sys_schedulejob;
import net.zoneland.greenleaf.timer.service.Log_timer_runlogServiceI;
import net.zoneland.greenleaf.timer.service.Sys_schedulejobServiceI;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.web.context.WebApplicationContext;


public class TaskUtils {
	
	public final static Logger log = Logger.getLogger(TaskUtils.class);
	private WebApplicationContext springContext = GLOBAL.springContext;
	/**
	 * 加载所有的定时任务
	 * 从数据库中获取所有的定时任务，并且启动定时任务
	 * 根据服务器IP来识别定时器是否运行指定的定时器
	 */
	public void runAllTask(){
		String hostip =null, hostname = null;
		boolean needRun = false;
		Sys_schedulejobServiceI sys_schedulejobService = (Sys_schedulejobServiceI)springContext.getBean("sys_schedulejobService");	
		
		try {
			hostip = InetAddress.getLocalHost().getHostAddress();
			hostname = InetAddress.getLocalHost().getHostName();
			log.info( "服务器获取到当前主机IP地址为：" + hostip +",    主机名称为：" +  hostname);
		} catch (UnknownHostException e) {
			log.error( "获取服务器到当前主机IP地址和主机名称发生异常。" +  e);
		}
		
		//这里获取任务信息数据
		Map<String, Object> paramMap =  new HashMap<String, Object>();
		paramMap.put("jobstatus", "1" );
		//paramMap.put("isautostart", 1 );
		List<Sys_schedulejob> jobList = sys_schedulejobService.getList(paramMap);
		if( jobList != null ){
			//log.debug("一共有["+jobList.size()+"]个定时任务需要加载，尝试加载定时任务......");
			for (Sys_schedulejob job : jobList) {
				needRun = false;
				//判断JOB的指定IP地址是否与主机的IP地址一致
				if("".equals(job.getRun_hostname()) || job.getRun_hostname() == null){
					//未配置，当前主机需要启动该定时任务
					log.info(">>>>>>>>>>定时任务["+job.getJobname()+"]未指定运行主机, 所有服务器均将加载定时任务......");
					needRun = true;
				}else if(job.getRun_hostname().equalsIgnoreCase(hostname) || job.getRun_hostname().equalsIgnoreCase(hostip)){
					log.info(">>>>>>>>>>该主机为定时任务["+job.getJobname()+"]加载指定主机, 加载任务......");
					needRun = true;
				}				
				if(needRun){
					log.debug("尝试加载定时任务:" + job.getJobname());
					addJob( job );
					log.info(">>>>>>>>>>定时任务[  "+job.getJobname()+"  ]加载完成。");
				}else{
					log.info(">>>>>>>>>>定时任务[  "+job.getJobname()+"  ]不需要加载，指定主机名为："+job.getRun_hostname()+"。");
				}
			}
			log.info("所有的定时任务已加载完成。");
		}
	}
	
	/**
	 * 停止所有的定时任务
	 * 从数据库中获取所有的定时任务，并且停止定时任务
	 */
	public void stopAllTask(){
		Sys_schedulejobServiceI sys_schedulejobService = (Sys_schedulejobServiceI)springContext.getBean("sys_schedulejobService");		 
		//这里获取任务信息数据
		Map<String, Object> paramMap =  new HashMap<String, Object>();
		List<Sys_schedulejob> jobList = sys_schedulejobService.getList(paramMap);
		if( jobList != null ){
			log.info(">>>>>>>>>>一共有["+jobList.size()+"]个定时任务需要加载，尝试停止定时任务......");
			for (Sys_schedulejob job : jobList) {
				log.debug("尝试停止定时任务:" + job.getJobname());
				try {
					deleteJob( job );
				} catch (SchedulerException e) {
					log.error("系统异常", e);
				}
				log.debug("定时任务["+job.getJobname()+"]停止完成。");
			}
			log.info("所有的定时任务已停止完成。");
		}
	}
	
	/**
	 * 启动执行一个定时任务
	 * @param schedulerFactoryBean
	 * @param job
	 */
	public void addJob( Sys_schedulejob job ){
		//从spring上下文中获取schedulerFactoryBean对象
		Scheduler scheduler = (Scheduler)springContext.getBean("schedulerFactoryBean");
		CronTrigger trigger = null;
		CronScheduleBuilder scheduleBuilder = null;
		TriggerKey triggerKey = null;
		//获取trigger，即在spring配置文件中定义的 bean id="myTrigger"
		try {
			triggerKey = TriggerKey.triggerKey(job.getJobname(), job.getJobgroup());
			trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
		} catch (SchedulerException e1) {
			log.error("系统异常", e1);
		}		 
		//不存在，创建一个
		if (null == trigger) {
			JobDetail jobDetail = JobBuilder.newJob(QuartzJobFactory.class).withIdentity(job.getJobname(), job.getJobgroup()).build();
			jobDetail.getJobDataMap().put("scheduleJob", job);
			//表达式调度构建器
			scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronexpression());
			//按新的cronExpression表达式构建一个新的trigger
			trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobname(), job.getJobgroup()).withSchedule(scheduleBuilder).build();
			try {
				scheduler.scheduleJob(jobDetail, trigger);
			} catch (SchedulerException e) {
				log.error("系统异常", e);
			}
		} else {
			// Trigger已存在，那么更新相应的定时设置
			//表达式调度构建器
			scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronexpression());
			//按新的cronExpression表达式重新构建trigger
			trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
			//按新的trigger重新设置job执行
			try {
				scheduler.rescheduleJob(triggerKey, trigger);
			} catch (SchedulerException e) {
				log.error("系统异常", e);
			}
		}
	}

	/**
	 * 通过反射调用scheduleJob中定义的方法
	 * 
	 * @param scheduleJob
	 */
	public static void invokMethod( Sys_schedulejob scheduleJob, JobExecutionContext context ) {		
		Object object = null;
		Class clazz = null;		
         //springId不为空先按springId查找bean
		if (StringUtils.isNotBlank(scheduleJob.getSpringid())) {
			object = GLOBAL.springContext.getBean(scheduleJob.getSpringid());
		} else if (StringUtils.isNotBlank(scheduleJob.getBeanclass())) {
			try {
				clazz = Class.forName(scheduleJob.getBeanclass());
				object = clazz.newInstance();
			} catch (Exception e) {
				log.error("系统异常", e);
			}
		}
		if (object == null) {
			log.error("任务名称 = [" + scheduleJob.getJobname() + "]---------------未启动成功，请检查是否配置正确！！！");
			return;
		}
		clazz = object.getClass();
		Method method = null;
		try {
			Method[] arr = clazz.getDeclaredMethods();
			
			for( Method _method : arr ){
				if(_method.getName().equalsIgnoreCase(scheduleJob.getMethodname())){
					method = _method;
				}
			}
			if( method == null ){
				log.error(clazz.getName() + "." + scheduleJob.getJobname() + "方法不存在！");
			}
			
		} catch (SecurityException e) {
			log.error("获取" + clazz.getName() + "." + scheduleJob.getJobname() + "方法发生权限错误！", e);
		}
		if (method != null) {
			Date jobTaskStartTime = null, jobTaskEndTime = null;
			jobTaskStartTime = new Date();
			log.info("invokMethod任务开始：" + jobTaskStartTime);
			
			try {				
				method.invoke(object, new Object[] {context});
			} catch (IllegalAccessException e) {
				log.error("系统异常", e);
			} catch (IllegalArgumentException e) {
				log.error("系统异常", e);
			} catch (InvocationTargetException e) {
				log.error("系统异常", e);
			}finally{
				jobTaskEndTime = new Date();
				log.info("invokMethod任务结束：" + jobTaskEndTime);
				DateOperation dateOperation = new DateOperation();
				
				//记录该定时任务运行消耗的时间
				Log_timer_runlog timer_runlog = new Log_timer_runlog();
				timer_runlog.setCall_continued(jobTaskEndTime.getTime() - jobTaskStartTime.getTime() );
				try {
					timer_runlog.setCall_starttime(dateOperation.getDateFromDate(jobTaskStartTime, "yyyy-MM-dd HH:mm:ss"));
				} catch (Exception e) {
					log.error("timer_runlog.setCall_starttime(dateOperation.getDateFromDate(jobTaskStartTime, \"yyyy-MM-dd HH:mm:ss\"));", e);
				}
				try {
					timer_runlog.setCall_endtime(dateOperation.getDateFromDate(jobTaskEndTime, "yyyy-MM-dd HH:mm:ss"));
				} catch (Exception e) {
					log.error("timer_runlog.setCall_endtime(dateOperation.getDateFromDate(jobTaskEndTime, \"yyyy-MM-dd HH:mm:ss\"));", e);
				}
				try{
					timer_runlog.setTimer_call_day(dateOperation.getDaysForMonth(jobTaskStartTime));
				}catch(ParseException e){
					log.error("timer_runlog.setTimer_call_day(dateOperation.getDaysForMonth(jobTaskStartTime));", e);
				}
				try{
					timer_runlog.setTimer_call_hour(Integer.parseInt(dateOperation.getHour(jobTaskStartTime)));
				}catch(NumberFormatException e){
					log.error("timer_runlog.setTimer_call_hour(Integer.parseInt(dateOperation.getHour(jobTaskStartTime)));", e);
				}
				try{
					timer_runlog.setTimer_call_month(Integer.parseInt(dateOperation.getMonth(jobTaskStartTime)));
				}catch(NumberFormatException e){
					log.error("timer_runlog.setTimer_call_month(Integer.parseInt(dateOperation.getMonth(jobTaskStartTime)));", e);
				}
				try{
					timer_runlog.setTimer_call_year(Integer.parseInt(dateOperation.getYear(jobTaskStartTime)));
				}catch(NumberFormatException e){
					log.error("timer_runlog.setTimer_call_year(Integer.parseInt(dateOperation.getYear(jobTaskStartTime)));", e);
				}
				timer_runlog.setTimer_id(scheduleJob.getJobid());
				timer_runlog.setTimer_name(scheduleJob.getJobname());
				timer_runlog.setThread_id(Thread.currentThread().getId() +"");
				timer_runlog.setThread_name(Thread.currentThread().getName() );
				
				Log_timer_runlogServiceI timer_runlogServiceI = (Log_timer_runlogServiceI)GLOBAL.springContext.getBean("log_timer_runlogService");
				try{
					timer_runlogServiceI.addOrUpdate(timer_runlog);
				}catch(Exception e){
					log.error("记录定时任务运行日志发生异常。" + e);
				}
			}
		}
	}
	
	/**
	 * 获取所有计划中的任务列表
	 * 
	 * @return
	 * @throws SchedulerException
	 */
	public List<Sys_schedulejob> getAllJob() throws SchedulerException {
		//从spring上下文中获取schedulerFactoryBean对象
		Scheduler scheduler = (Scheduler)springContext.getBean("schedulerFactoryBean");
		GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
		Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
		List<Sys_schedulejob> jobList = new ArrayList<Sys_schedulejob>();
		for (JobKey jobKey : jobKeys) {
			List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
			for (Trigger trigger : triggers) {
				Sys_schedulejob job = new Sys_schedulejob();
				job.setJobname(jobKey.getName());
				job.setJobgroup(jobKey.getGroup());
				job.setDescription("触发器:" + trigger.getKey());
				Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
				job.setJobstatus(triggerState.name());
				if (trigger instanceof CronTrigger) {
					CronTrigger cronTrigger = (CronTrigger) trigger;
					String cronExpression = cronTrigger.getCronExpression();
					job.setCronexpression(cronExpression);
				}
				jobList.add(job);
			}
		}
		return jobList;
	}
	
	/**
	 * 所有正在运行的job
	 * 
	 * @return
	 * @throws SchedulerException
	 */
	public List<Sys_schedulejob> getRunningJob() throws SchedulerException {
		//从spring上下文中获取schedulerFactoryBean对象
		Scheduler scheduler = (Scheduler)springContext.getBean("schedulerFactoryBean");
		List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
		List<Sys_schedulejob> jobList = new ArrayList<Sys_schedulejob>(executingJobs.size());
		for (JobExecutionContext executingJob : executingJobs) {
			Sys_schedulejob job = new Sys_schedulejob();
			JobDetail jobDetail = executingJob.getJobDetail();
			JobKey jobKey = jobDetail.getKey();
			Trigger trigger = executingJob.getTrigger();
			job.setJobname(jobKey.getName());
			job.setJobgroup(jobKey.getGroup());
			job.setDescription("触发器:" + trigger.getKey());
			Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
			job.setJobstatus(triggerState.name());
			if (trigger instanceof CronTrigger) {
				CronTrigger cronTrigger = (CronTrigger) trigger;
				String cronExpression = cronTrigger.getCronExpression();
				job.setCronexpression(cronExpression);
			}
			jobList.add(job);
		}
		return jobList;
	}
	
	/**
	 * 暂停一个job
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void pauseJob(Sys_schedulejob scheduleJob) throws SchedulerException {
		//从spring上下文中获取schedulerFactoryBean对象
		Scheduler scheduler = (Scheduler)springContext.getBean("schedulerFactoryBean");
		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobname(), scheduleJob.getJobgroup());
		scheduler.pauseJob(jobKey);
	}

	/**
	 * 恢复一个job
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void resumeJob(Sys_schedulejob scheduleJob) throws SchedulerException {
		//从spring上下文中获取schedulerFactoryBean对象
		Scheduler scheduler = (Scheduler)springContext.getBean("schedulerFactoryBean");
		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobname(), scheduleJob.getJobgroup());
		scheduler.resumeJob(jobKey);
	}

	/**
	 * 删除一个job
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void deleteJob(Sys_schedulejob scheduleJob) throws SchedulerException {
		//从spring上下文中获取schedulerFactoryBean对象
		Scheduler scheduler = (Scheduler)springContext.getBean("schedulerFactoryBean");
		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobname(), scheduleJob.getJobgroup());
		scheduler.deleteJob(jobKey);
	}

	/**
	 * 立即执行job
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void runAJobNow(Sys_schedulejob scheduleJob) throws SchedulerException {
		//从spring上下文中获取schedulerFactoryBean对象
		Scheduler scheduler = (Scheduler)springContext.getBean("schedulerFactoryBean");
		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobname(), scheduleJob.getJobgroup());
		scheduler.triggerJob(jobKey);
	}

	/**
	 * 更新job时间表达式
	 * 
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void updateJobCron(Sys_schedulejob scheduleJob) throws SchedulerException {
		//从spring上下文中获取schedulerFactoryBean对象
		Scheduler scheduler = (Scheduler)springContext.getBean("schedulerFactoryBean");
		TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobname(), scheduleJob.getJobgroup());
		CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
		CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronexpression());
		if( trigger!=null){
			trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
			scheduler.rescheduleJob(triggerKey, trigger);
		}
	}
}